package com.ybt.message.pack.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;

import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;

import com.ruleengine.context.IContextProperty;
import com.ruleengine.context.IWorkflowConext;
import com.sinosoft.midplat.common.JdomUtil;
import com.ybt.message.constant.FixedLengthConstants;
import com.ybt.message.pack.IMessagePack;
import com.ybt.message.pack.MessagePackDecorator;
import com.ybt.message.pack.exception.MessagePackException;

public class FixedLengthPack extends MessagePackDecorator{
    private static Logger logger = Logger.getLogger(FixedLengthPack.class);
    
    public FixedLengthPack(IMessagePack pack) {
        super(pack);
        // TODO Auto-generated constructor stub
    }

    public Object packMessage(IWorkflowConext context, Object message) throws MessagePackException {
        // TODO Auto-generated method stub
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            // 渠道
            String channel = config.getAttributeValue(
                    FixedLengthConstants.ARRT_TAG_CHANNEL);

            // 字节编码
            String encode = config.getAttributeValue(
                    FixedLengthConstants.ARRT_TAG_ENCODE);
            // 报文体字段内容
            byte[] body = null;

            // 报文体
            Document result = null;
            List<Element> items = config.getChildren(
                    FixedLengthConstants.ELE_TAG_ITEM);
            for (Element ie : items) {
                // 解析每个定长字段
                // 字段长度
                String strLength = ie
                        .getAttributeValue(FixedLengthConstants.ARRT_TAG_LENGTH);
                int length = -1;
                if (strLength != null) {
                    length = Integer.parseInt(strLength);
                }
                
                // 字段对齐方式
                String align = ie
                        .getAttributeValue(FixedLengthConstants.ARRT_TAG_ALIGN);
                // 字段填充值
                String fill = ie
                        .getAttributeValue(FixedLengthConstants.ARRT_TAG_FILL);
                // 字段值
                String value = ie
                .getAttributeValue(FixedLengthConstants.ARRT_TAG_VALUE);
                if (value.startsWith(FixedLengthConstants.ARRT_VALUE_CONTEXT)) {
                    // 值来自于context中
                    String key = value.substring(FixedLengthConstants.ARRT_VALUE_CONTEXT.length());
                    IContextProperty<?> tranPro = context.getContextProperty(key);
                    if(tranPro==null){
                        throw new MessagePackException("there isn't a property named ["+ key + "] in context");
                    }
                    logger.debug("pack the item ["+ key+":"+tranPro.getValue()+"]");
                    //写入数据
                    out.write(tranPro.getValue().toString().getBytes(encode));
                } else if (FixedLengthConstants.ARRT_VALUE_BODYLENGTH.equals(value)) {
                    // 值为报文体的长度
                    if(message instanceof String){
                        body = ((String)message).getBytes(encode);
                    }else if(message instanceof Document){
                        body = JdomUtil.toBytes((Document)message, encode);
                    }else if(message instanceof byte[]){
                        body = (byte[])message;
                    }else{
                        throw new MessagePackException("unsupport parameter type of message ["+ body.getClass() + "]");
                    }
                    String bodylength = body.length+"";
                    
                    if(length != -1){
                        //该字段有长度限制
                        if(bodylength.length()>length){
                            //实际报文长度大于该字段的位数
                            throw new MessagePackException("the length of message body is larger than the limited, " + bodylength +" > "+ length);
                        }else{
                            //位数不足，补位
                            if(FixedLengthConstants.ARRT_ALIGN_LEFT.equals(align)){
                                //左补位
                                if(fill != null){
                                    //自定义符号
                                    while(bodylength.length()<length){
                                        bodylength = fill+bodylength;
                                    }
                                }else{
                                    //默认左补0
                                    while(bodylength.length()<length){
                                        bodylength = "0"+bodylength;
                                    }
                                }
                            }else{
                                //右补位
                                if(fill != null){
                                    //自定义符号
                                    while(bodylength.length()<length){
                                        bodylength = bodylength + fill;
                                    }
                                }else{
                                    //默认右补空格
                                    while(bodylength.length()<length){
                                        bodylength =bodylength + " ";
                                    }
                                }
                            }
                        }
                    }
                    logger.debug("pack the item ["+ value+":"+bodylength+"]");
                    //写入报文长度数据
                    out.write(bodylength.getBytes(encode));
                }else{
                    throw new MessagePackException("unsupport value type [" + value +"] in pack configration file of channel : "+ channel);
                }
            }
            //写入报文体
            logger.debug("pack the message body :" + new String(body,encode));
            out.write(body);
            return out.toByteArray();
        } catch (UnsupportedEncodingException e) {
            throw new MessagePackException(e);
        } catch (IOException e) {
            throw new MessagePackException(e);
        }
    }
}
